"""
数据库连接和会话管理模块

负责数据库连接池管理、会话创建和资源清理。
支持 MySQL 主数据库和 Redis 缓存数据库的连接管理。

主要功能：
1. 数据库引擎创建和配置
2. 会话工厂创建
3. 连接池管理
4. Redis 连接管理
5. 数据库初始化和清理

作者: LLM Chat System
版本: 1.0.0
"""

from sqlalchemy import create_engine, MetaData
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session
from sqlalchemy.pool import QueuePool
import redis
from typing import Generator

from app.core.config import settings

# ==================== 数据库引擎配置 ====================
# 创建 MySQL 数据库引擎，配置连接池参数
engine = create_engine(
    settings.database_url,        # 数据库连接 URL
    poolclass=QueuePool,          # 使用队列连接池
    pool_size=10,                 # 连接池大小
    max_overflow=20,              # 最大溢出连接数
    pool_pre_ping=True,           # 连接前检查连接是否有效
    echo=settings.debug           # 调试模式下显示 SQL 语句
)

# ==================== 会话管理 ====================
# 创建数据库会话工厂
SessionLocal = sessionmaker(
    autocommit=False,             # 不自动提交事务
    autoflush=False,              # 不自动刷新会话
    bind=engine                   # 绑定到数据库引擎
)

# ==================== 模型基类 ====================
# 创建 SQLAlchemy 模型基类
# 所有数据库模型都继承自这个基类
Base = declarative_base()

# 创建元数据对象
# 用于数据库迁移和表结构管理
metadata = MetaData()

# ==================== Redis 连接 ====================
# 创建 Redis 客户端连接
redis_client = redis.from_url(
    settings.redis_url,           # Redis 连接 URL
    decode_responses=True         # 自动解码响应为字符串
)


def get_db() -> Generator[Session, None, None]:
    """
    获取数据库会话
    
    用于 FastAPI 依赖注入，确保每个请求都有独立的数据库会话。
    使用生成器模式，在请求结束时自动关闭会话。
    
    Yields:
        Session: 数据库会话对象
        
    Example:
        ```python
        @app.get("/users/")
        async def get_users(db: Session = Depends(get_db)):
            return db.query(User).all()
        ```
    """
    db = SessionLocal()  # 创建新的数据库会话
    try:
        yield db         # 返回会话给调用者
    finally:
        db.close()       # 确保会话被正确关闭


def get_redis() -> redis.Redis:
    """
    获取 Redis 连接
    
    返回全局 Redis 客户端实例，用于缓存操作。
    
    Returns:
        redis.Redis: Redis 客户端实例
    """
    return redis_client


def init_db():
    """
    初始化数据库
    
    创建所有数据库表结构。在应用启动时调用。
    会自动导入所有模型类，确保它们被注册到 SQLAlchemy 元数据中。
    """
    # 导入所有模型以确保它们被注册到 SQLAlchemy 元数据中
    # 注意：导入顺序很重要，被引用的模型需要先导入
    from app.models.model_config import ModelConfig
    from app.models.prompt_template import PromptTemplate
    from app.models.knowledge_base import KnowledgeBase, Document
    from app.models.conversation import Conversation, Message
    from app.models.user import User
    from app.models.user_settings import UserSettings
    from app.models.todo import Todo
    
    # 根据模型定义创建所有数据库表
    Base.metadata.create_all(bind=engine)


def close_db():
    """
    关闭数据库连接
    
    清理数据库连接池和 Redis 连接。
    在应用关闭时调用，释放所有数据库资源。
    """
    engine.dispose()        # 关闭数据库引擎和连接池
    redis_client.close()    # 关闭 Redis 连接
